﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using LED_Editor.Model;

namespace LED_Editor.ControllerProgramming {
	public class XtendedSerialPortProgrammingStrategy : ExtendedControllerProgrammingStrategy {
		private const string ComPortIsNull = "ComPort не проинициализирован (null)";
		public XtendedSerialPortProgrammingStrategy(SerialPort comPort)
			: base() {
			if (comPort == null)
				throw new ArgumentNullException(ComPortIsNull);
			ComPort = comPort;
		}

		public SerialPort getPort() {
			return ComPort;
		}

		private SerialPort ComPort { get; set; }

		public override void OpenConnection() {
			if (ComPort == null)
				throw new InvalidOperationException(ComPortIsNull);

			if (!ComPort.IsOpen) {
				ComPort.Open();
				base.OpenConnection();
			}
		}


		public override void CloseConnection() {
			if (ComPort == null)
				throw new InvalidOperationException(ComPortIsNull);

			if (ComPort.IsOpen) {
				ComPort.Close();
				base.CloseConnection();
			}
		}

		public override void SendQuery(byte[] query) {
			ComPort.Write(query, 0, query.Length);
			base.SendQuery(query);
		}

		public override bool IsOpen { get { return ComPort.IsOpen; } }

		public override int Timeout {
			get {
				return Math.Max(ComPort.ReadTimeout, ComPort.WriteTimeout);
			}
			set {
				ComPort.ReadTimeout = value;
				ComPort.WriteTimeout = value;
			}
		}

		public override object WaitAnswer() {
			try {
				// Log("     Ожидание ответа...");

				Query answer = null;
				byte[] answerBytes = new byte[8];
				ComPort.DiscardInBuffer();
				for (int i = 0; i < 8; i++)
					ComPort.Read(answerBytes, i, 1);
				while (true) {
					answer = QueryParser.Instance.Parse(answerBytes);

					if (answer.Address == Address || answer.Address == 0)
						break;
				}

				Log("<-   Ответ: " + answer.ToString());
				return answer;
			} catch (InvalidOperationException e) {
				throw new ControllerException("Ошибка чтения последовательного порта", e);
			} catch (TimeoutException e) {
				throw new ControllerException("Превышено время ожидания при чтении последовательного порта", e);
			}
		}
	}
}
